import { Snake } from '../entities/Snake';
import { Food } from '../entities/Food';
import { Vector2D } from '../utils/Vector2D';
import { EnvironmentManager, Weather, TimeOfDay, Trap } from './EnvironmentManager';
import { EffectType, SnakeEffectManager } from './SnakeEffectManager';

export class Renderer {

    // 膨胀参数
    private readonly BASE_SCALE = 1.0;
    private readonly SCALE_INCREMENT = 0.005; // 每节增加0.5%
    private readonly MAX_SCALE = 1.5; // 最大150%

    constructor(
        private ctx: CanvasRenderingContext2D,
        private environmentManager: EnvironmentManager
    ) {}

    public render(snake: Snake, foods: Food[]): void {
        // 渲染背景
        this.renderBackground();

        // 渲染天气效果
        this.renderWeather();

        // 渲染陷阱
        this.renderTraps();

        // 渲染食物
        this.renderFoods(foods);
        
        // 渲染蛇
        this.renderSnake(snake);
    }

    private renderBackground(): void {
        const timeOfDay = this.environmentManager.getTimeOfDay();
        const canvas = this.ctx.canvas;

        // 创建渐变背景
        const gradient = this.ctx.createLinearGradient(0, 0, 0, canvas.height);
        switch (timeOfDay) {
            case 'dawn':
                gradient.addColorStop(0, '#FF7F50');
                gradient.addColorStop(1, '#FFB6C1');
                break;
            case 'day':
                gradient.addColorStop(0, '#87CEEB');
                gradient.addColorStop(1, '#E0FFFF');
                break;
            case 'dusk':
                gradient.addColorStop(0, '#FF6B6B');
                gradient.addColorStop(1, '#4A90E2');
                break;
            case 'night':
                gradient.addColorStop(0, '#191970');
                gradient.addColorStop(1, '#000080');
                break;
        }

        this.ctx.fillStyle = gradient;
        this.ctx.fillRect(0, 0, canvas.width, canvas.height);
    }

    private renderWeather(): void {
        const weather = this.environmentManager.getWeather();
        const canvas = this.ctx.canvas;

        switch (weather) {
            case 'rain':
                this.renderRain(canvas.width, canvas.height);
                break;
            case 'snow':
                this.renderSnow(canvas.width, canvas.height);
                break;
        }
    }

    private renderRain(width: number, height: number): void {
        const raindrops = 100;
        this.ctx.strokeStyle = 'rgba(174, 194, 224, 0.5)';
        this.ctx.lineWidth = 1;

        for (let i = 0; i < raindrops; i++) {
            const x = Math.random() * width;
            const y = Math.random() * height;
            
            this.ctx.beginPath();
            this.ctx.moveTo(x, y);
            this.ctx.lineTo(x + 10, y + 10);
            this.ctx.stroke();
        }
    }

    private renderSnow(width: number, height: number): void {
        const snowflakes = 50;
        this.ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';

        for (let i = 0; i < snowflakes; i++) {
            const x = Math.random() * width;
            const y = Math.random() * height;
            const radius = Math.random() * 2 + 1;

            this.ctx.beginPath();
            this.ctx.arc(x, y, radius, 0, Math.PI * 2);
            this.ctx.fill();
        }
    }

    private renderTraps(): void {
        const traps = this.environmentManager.getTraps();
        
        traps.forEach(trap => {
            switch (trap.type) {
                case 'spike':
                    this.renderSpikeTrap(trap);
                    break;
                case 'portal':
                    this.renderPortalTrap(trap);
                    break;
                case 'slowField':
                    this.renderSlowFieldTrap(trap);
                    break;
            }
        });
    }

    private renderSpikeTrap(trap: Trap): void {
        const { x, y } = trap.position;
        this.ctx.fillStyle = 'rgba(255, 0, 0, 0.6)';
        
        // 绘制尖刺形状
        this.ctx.beginPath();
        this.ctx.moveTo(x - 10, y + 10);
        this.ctx.lineTo(x, y - 10);
        this.ctx.lineTo(x + 10, y + 10);
        this.ctx.closePath();
        this.ctx.fill();
    }

    private renderPortalTrap(trap: Trap): void {
        const { x, y } = trap.position;
        const gradient = this.ctx.createRadialGradient(x, y, 0, x, y, 15);
        
        gradient.addColorStop(0, 'rgba(138, 43, 226, 0.8)');
        gradient.addColorStop(1, 'rgba(138, 43, 226, 0)');
        
        this.ctx.fillStyle = gradient;
        this.ctx.beginPath();
        this.ctx.arc(x, y, 15, 0, Math.PI * 2);
        this.ctx.fill();
    }

    private renderSlowFieldTrap(trap: Trap): void {
        const { x, y } = trap.position;
        const gradient = this.ctx.createRadialGradient(x, y, 0, x, y, 20);
        
        gradient.addColorStop(0, 'rgba(0, 191, 255, 0.3)');
        gradient.addColorStop(1, 'rgba(0, 191, 255, 0)');
        
        this.ctx.fillStyle = gradient;
        this.ctx.beginPath();
        this.ctx.arc(x, y, 20, 0, Math.PI * 2);
        this.ctx.fill();
    }

    private renderSnake(snake: Snake): void {
        const segments = snake.getSegments();
        const head = segments[0];
        const currentSkin = document.body.getAttribute('data-snake-skin') || 'default';
        const effectManager = snake.getEffectManager();
        const activeEffects = effectManager.getActiveEffects();
        
        // 渲染粒子效果（在蛇身后面）
        this.renderParticles(effectManager);
        
        // 渲染能量场效果
        if (activeEffects.has('energyField')) {
            this.renderEnergyField(segments, activeEffects.get('energyField')!);
        }
        
        // 渲染空间扭曲效果
        if (activeEffects.has('spaceDistortion')) {
            this.renderSpaceDistortion(segments, activeEffects.get('spaceDistortion')!);
        }

        // 渲染蛇身
        for (let i = segments.length - 1; i >= 0; i--) {
            const segment = segments[i];
            const baseRadius = i === 0 ? 15 : 12; // 头部稍大
            
            // 应用渐进膨胀效果
            const scale = Math.min(
                this.MAX_SCALE,
                this.BASE_SCALE + (segments.length * this.SCALE_INCREMENT)
            )
            // const scale = effectManager.getSegmentScale(i);
            const radius = baseRadius * scale;
            
            const alpha = 0.8 - (i / segments.length) * 0.5; // 渐变透明度

            // 创建一个临时的DOM元素来应用皮肤样式
            const segmentElement = document.createElement('div');
            segmentElement.className = `snake-segment skin-${currentSkin}`;
            document.body.appendChild(segmentElement);

            // 获取计算后的样式
            const computedStyle = window.getComputedStyle(segmentElement);
            const backgroundColor = computedStyle.backgroundColor;
            const boxShadow = computedStyle.boxShadow;

            // 清理临时元素
            document.body.removeChild(segmentElement);

            // 应用样式到Canvas渲染
            this.ctx.beginPath();
            this.ctx.arc(segment.x, segment.y, radius, 0, Math.PI * 2);
            
            // 根据皮肤类型应用不同的渲染效果
            switch(currentSkin) {
                case 'neon':
                    // 霓虹渐变效果
                    const neonGradient = this.ctx.createLinearGradient(
                        segment.x - radius, segment.y - radius,
                        segment.x + radius, segment.y + radius
                    );
                    neonGradient.addColorStop(0, '#ff00ff');
                    neonGradient.addColorStop(0.5, '#00ffff');
                    neonGradient.addColorStop(1, '#ff00ff');
                    this.ctx.fillStyle = neonGradient;
                    this.ctx.shadowColor = 'rgba(255,0,255,0.5)';
                    this.ctx.shadowBlur = 15;
                    break;
                    
                case 'metal':
                    // 金属条纹效果
                    const metalGradient = this.ctx.createLinearGradient(
                        segment.x - radius, segment.y - radius,
                        segment.x + radius, segment.y + radius
                    );
                    metalGradient.addColorStop(0, '#B0BEC5');
                    metalGradient.addColorStop(0.25, '#ECEFF1');
                    metalGradient.addColorStop(0.5, '#B0BEC5');
                    metalGradient.addColorStop(0.75, '#ECEFF1');
                    metalGradient.addColorStop(1, '#B0BEC5');
                    this.ctx.fillStyle = metalGradient;
                    this.ctx.shadowColor = 'rgba(176,190,197,0.7)';
                    this.ctx.shadowBlur = 10;
                    break;
                    
                case 'spots':
                    // 动态斑点效果
                    this.ctx.fillStyle = '#8BC34A';
                    break;
                    
                case 'ghost':
                    // 半透明幻影效果
                    this.ctx.globalAlpha = 0.3;
                    this.ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
                    this.ctx.shadowColor = 'rgba(255,255,255,0.5)';
                    this.ctx.shadowBlur = 15;
                    break;
                    
                default:
                case 'default':
                    // 默认绿色
                    this.ctx.fillStyle = '#4CAF50';
                    this.ctx.shadowColor = 'rgba(76,175,80,0.5)';
                    this.ctx.shadowBlur = 5;
                    break;
            }
            
            this.ctx.fill();
            this.ctx.closePath();
            
            // 为斑点皮肤添加斑点
            if (currentSkin === 'spots') {
                const spotRadius = radius / 3;
                this.ctx.fillStyle = '#FFEB3B';
                
                // 斑点1
                this.ctx.beginPath();
                this.ctx.arc(segment.x - radius/3, segment.y - radius/3, spotRadius, 0, Math.PI * 2);
                this.ctx.fill();
                
                // 斑点2
                this.ctx.beginPath();
                this.ctx.arc(segment.x + radius/4, segment.y + radius/4, spotRadius, 0, Math.PI * 2);
                this.ctx.fill();
                
                // 斑点3
                this.ctx.beginPath();
                this.ctx.arc(segment.x + radius/2, segment.y - radius/3, spotRadius, 0, Math.PI * 2);
                this.ctx.fill();
            }
            
            // 如果是幽灵皮肤，添加边框
            if (currentSkin === 'ghost') {
                this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
                this.ctx.lineWidth = 1;
                this.ctx.stroke();
                this.ctx.globalAlpha = 1; // 恢复透明度
            }

            // 重置阴影效果
            this.ctx.shadowBlur = 0;
            
            // 渲染脉动光效（≥20节）
            if (activeEffects.has('pulse')) {
                this.renderPulseEffect(segment, radius, activeEffects.get('pulse')!);
            }
        }
        
        // 渲染幻影拖尾效果（≥50节）
        if (activeEffects.has('trail')) {
            this.renderTrailEffect(segments, activeEffects.get('trail')!);
        }
    }
    
    /**
     * 渲染脉动光效
     */
    private renderPulseEffect(position: Vector2D, radius: number, effect: { intensity: number, color: string }): void {
        const pulseTime = Date.now() % 2000 / 2000; // 0-1循环
        const pulseSize = radius * (1 + 0.3 * Math.sin(pulseTime * Math.PI * 2) * effect.intensity);
        
        this.ctx.beginPath();
        this.ctx.arc(position.x, position.y, pulseSize, 0, Math.PI * 2);
        this.ctx.fillStyle = `rgba(255, 255, 255, ${0.1 * effect.intensity})`;
        this.ctx.fill();
        
        // 添加光环
        this.ctx.beginPath();
        this.ctx.arc(position.x, position.y, radius * 1.5, 0, Math.PI * 2);
        this.ctx.strokeStyle = `rgba(255, 255, 255, ${0.2 * effect.intensity * (0.5 + 0.5 * Math.sin(pulseTime * Math.PI * 4))})`;
        this.ctx.lineWidth = 2;
        this.ctx.stroke();
    }
    
    /**
     * 渲染幻影拖尾效果
     */
    private renderTrailEffect(segments: Vector2D[], effect: { intensity: number, color: string }): void {
        const trailLength = Math.min(10, Math.floor(segments.length / 5));
        
        for (let i = 0; i < segments.length; i += 5) {
            if (i + 1 >= segments.length) continue;
            
            const segment = segments[i];
            const nextSegment = segments[i + 1];
            
            // 创建渐变
            const gradient = this.ctx.createLinearGradient(
                segment.x, segment.y,
                nextSegment.x, nextSegment.y
            );
            
            gradient.addColorStop(0, `rgba(173, 216, 230, ${0.7 * effect.intensity})`);
            gradient.addColorStop(1, `rgba(173, 216, 230, 0)`);
            
            // 绘制拖尾线
            this.ctx.beginPath();
            this.ctx.moveTo(segment.x, segment.y);
            this.ctx.lineTo(nextSegment.x, nextSegment.y);
            this.ctx.lineWidth = 8;
            this.ctx.strokeStyle = gradient;
            this.ctx.stroke();
        }
    }
    
    /**
     * 渲染能量场效果
     */
    private renderEnergyField(segments: Vector2D[], effect: { intensity: number, color: string }): void {
        const head = segments[0];
        const fieldRadius = 100 * effect.intensity;
        
        // 创建径向渐变
        const gradient = this.ctx.createRadialGradient(
            head.x, head.y, 0,
            head.x, head.y, fieldRadius
        );
        
        gradient.addColorStop(0, `rgba(255, 170, 0, ${0.3 * effect.intensity})`);
        gradient.addColorStop(1, 'rgba(255, 170, 0, 0)');
        
        // 绘制能量场
        this.ctx.beginPath();
        this.ctx.arc(head.x, head.y, fieldRadius, 0, Math.PI * 2);
        this.ctx.fillStyle = gradient;
        this.ctx.fill();
        
        // 添加能量波纹
        const waveTime = Date.now() % 3000 / 3000; // 0-1循环
        const waveRadius = fieldRadius * waveTime;
        
        this.ctx.beginPath();
        this.ctx.arc(head.x, head.y, waveRadius, 0, Math.PI * 2);
        this.ctx.strokeStyle = `rgba(255, 170, 0, ${0.5 * effect.intensity * (1 - waveTime)})`;
        this.ctx.lineWidth = 3;
        this.ctx.stroke();
    }
    
    /**
     * 渲染空间扭曲效果
     */
    private renderSpaceDistortion(segments: Vector2D[], effect: { intensity: number, color: string }): void {
        const head = segments[0];
        const distortionRadius = 150 * effect.intensity;
        
        // 保存当前上下文状态
        this.ctx.save();
        
        // 创建径向渐变
        const gradient = this.ctx.createRadialGradient(
            head.x, head.y, 0,
            head.x, head.y, distortionRadius
        );
        
        gradient.addColorStop(0, `rgba(255, 0, 255, ${0.2 * effect.intensity})`);
        gradient.addColorStop(0.7, `rgba(128, 0, 255, ${0.1 * effect.intensity})`);
        gradient.addColorStop(1, 'rgba(0, 0, 255, 0)');
        
        // 绘制扭曲场
        this.ctx.beginPath();
        this.ctx.arc(head.x, head.y, distortionRadius, 0, Math.PI * 2);
        this.ctx.fillStyle = gradient;
        this.ctx.fill();
        
        // 添加扭曲线
        const lineCount = 8;
        const time = Date.now() / 1000;
        
        for (let i = 0; i < lineCount; i++) {
            const angle = (Math.PI * 2 * i) / lineCount + time * 0.5;
            const innerRadius = distortionRadius * 0.2;
            const outerRadius = distortionRadius * 0.8;
            
            const startX = head.x + Math.cos(angle) * innerRadius;
            const startY = head.y + Math.sin(angle) * innerRadius;
            
            const endX = head.x + Math.cos(angle) * outerRadius;
            const endY = head.y + Math.sin(angle) * outerRadius;
            
            // 创建线性渐变
            const lineGradient = this.ctx.createLinearGradient(startX, startY, endX, endY);
            lineGradient.addColorStop(0, `rgba(255, 0, 255, ${0.7 * effect.intensity})`);
            lineGradient.addColorStop(1, `rgba(0, 0, 255, 0)`);
            
            this.ctx.beginPath();
            this.ctx.moveTo(startX, startY);
            this.ctx.lineTo(endX, endY);
            this.ctx.lineWidth = 2;
            this.ctx.strokeStyle = lineGradient;
            this.ctx.stroke();
        }
        
        // 恢复上下文状态
        this.ctx.restore();
    }
    
    /**
     * 渲染粒子效果
     */
    private renderParticles(effectManager: SnakeEffectManager): void {
        const particles = effectManager.getParticles();
        
        for (const particle of particles) {
            const alpha = particle.life / particle.maxLife;
            
            this.ctx.beginPath();
            this.ctx.arc(
                particle.position.x,
                particle.position.y,
                particle.size,
                0,
                Math.PI * 2
            );
            
            // 创建径向渐变
            const gradient = this.ctx.createRadialGradient(
                particle.position.x, particle.position.y, 0,
                particle.position.x, particle.position.y, particle.size
            );
            
            gradient.addColorStop(0, `${particle.color}`);
            gradient.addColorStop(1, `rgba(255, 255, 255, 0)`);
            
            this.ctx.fillStyle = gradient;
            this.ctx.globalAlpha = alpha;
            this.ctx.fill();
            this.ctx.globalAlpha = 1;
        }
    }

    private renderFoods(foods: Food[]): void {
        foods.forEach(food => {
            const position = food.getPosition();
            const baseSize = food.getSize();
            
            this.ctx.save();
            
            // 绘制食物主体
            this.ctx.beginPath();
            this.ctx.fillStyle = food.getColor();
            this.ctx.arc(position.x, position.y, baseSize, 0, Math.PI * 2);
            this.ctx.fill();

            // 为毒苹果添加警告标记
            if (food.getType() === 'poison') {
                this.ctx.strokeStyle = '#FFFFFF';
                this.ctx.lineWidth = 2;
                this.ctx.beginPath();
                this.ctx.moveTo(position.x - baseSize/2, position.y);
                this.ctx.lineTo(position.x + baseSize/2, position.y);
                this.ctx.moveTo(position.x, position.y - baseSize/2);
                this.ctx.lineTo(position.x, position.y + baseSize/2);
                this.ctx.stroke();
            }

            // 为磁核果实添加磁场效果
            if (food.getType() === 'magnet') {
                this.ctx.strokeStyle = food.getColor();
                this.ctx.lineWidth = 2;
                this.ctx.globalAlpha = 0.5;
                this.ctx.beginPath();
                this.ctx.arc(position.x, position.y, baseSize * 1.5, 0, Math.PI * 2);
                this.ctx.stroke();
            }

            this.ctx.restore();
        });
    }
}